﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace rmfastwin
{
    public class DeleteInfo
    {
        public string path;
        public bool done;
        public int filecount;
        public int deletecount;
        public int errorcount;
    }
    public class DeleteTask
    {
        public DeleteTask(string path)
        {
            this.info = new DeleteInfo();
            info.path = path;
            info.done = false;
            info.filecount = 0;
            info.deletecount = 0;
            info.errorcount = 0;

            works = new Thread[5];
            for (var i = 0; i < works.Length; i++)
            {
                var t = new Thread(ThreadDeleteWorker);
                t.IsBackground = true;
                t.Start();
            }

            {
                var t = new Thread(ThreadListPath);
                t.IsBackground = true;
                t.Start();
            }


        }
        public enum CmdType
        {
            ListFile,
            DeletePath,
        }
        public class Cmd
        {
            public CmdType type;
            public string path;
        }
        int subpathcount = 0;
        int delpathcount = 0;
        System.Collections.Concurrent.ConcurrentQueue<string> subpath = new System.Collections.Concurrent.ConcurrentQueue<string>();
        void ThreadDeleteWorker()
        {
            while (true)
            {
                if (subpath.TryDequeue(out var path))
                {
                    DeletePath(path);
                    Interlocked.Increment(ref delpathcount);
                    if (subpathcount > 0 && subpathcount == delpathcount)
                    {
                        info.done = true;
                        System.IO.Directory.Delete(info.path, true);
                    }
                }
                else
                {

                    System.Threading.Thread.Sleep(1);
                }
            }
        }
        void ThreadListPath()
        {
            subpath.Enqueue(info.path);
            subpathcount = ListFile(info.path) + 1;

        }
        int ListFile(string path)
        {
            var dirs = System.IO.Directory.GetDirectories(path);
            if (dirs.Length == 0)
                return 0;
            

            int len = 0;
            foreach (var p in dirs)
            {
                subpath.Enqueue(p);
                len++;

                len += ListFile(p);
            }
            return len;
        }
        void DeletePath(string path)
        {
            var files = System.IO.Directory.GetFiles(path);
            info.filecount += files.Length;
            foreach (var f in files)
            {
                try
                {
                    info.deletecount++;
                    System.IO.File.SetAttributes(f, System.IO.FileAttributes.Normal);
                    System.IO.File.Delete(f);
                }
                catch
                {
                    info.errorcount++;
                }
            }
        }
        public DeleteInfo info;
        Thread[] works = null;
    }

    public static class DeleteTool
    {

        static System.Collections.Concurrent.ConcurrentDictionary<string, DeleteTask> tasks = new System.Collections.Concurrent.ConcurrentDictionary<string, DeleteTask>();
        public static bool StartDeletePath(string path)
        {

            if (tasks.TryGetValue(path, out var v))
            {
                if (v.info.done)
                {
                    tasks[path] = new DeleteTask(path);
                    return true;
                }
                return false;
            }
            else
            {
                tasks[path] = new DeleteTask(path);
                return true;
            }
        }
        public static DeleteInfo GetInfo(string path)
        {
            if (tasks.TryGetValue(path, out var v))
            {
                return v.info;
            }
            return null;
        }

    }
}
